#pragma once
#pragma once
#include <memory>
#include <unordered_map>
#include <unistd.h>
#include <sys/select.h>
#include <unordered_map>

#include "Socket.hpp"
#include "Server.hpp"
#include "ClientInfo.hpp"
#include "Log.hpp"
#include "Error.hpp"
#include "thread.hpp"

// 写出echo服务器

class TcpServer : public Server
{
public:
    struct Tcp_Client
    {
        TcpServer *pthis;
        int fd;
        std::string name;
    };
    using ptr = std::unique_ptr<TcpServer>;
    TcpServer()
    {
    }
    int AcceptHandler()
    {
        Client cli;
        int sock = _listensock.Accept(&cli._ip, &cli._port);
        _clients[sock] = cli;
        return sock;
    }

    // 1.先测试echo 服务器
    void ReadHandler(int fd)
    {
        while (true)
        {
            cout << "------------" << endl;
            // 此时进行读，是不会被阻塞的，因为select通知我读事件已经就绪了
            // recv(int sockfd, void *buf, size_t len, int flags);
            char buf[1024];
            int n = recv(fd, buf, sizeof(buf), 0);
            if (n == 0)
            {
                LOG(INFO, "对端 关闭");
                break;
            }
            else if (n > 0)
            {
                buf[n] = 0;
                cout << buf << endl;
                std::string msg = "server";
                msg += buf;
                // 在多路转接中一般写事件不关心
                // 因为大部分情况下，写事件是就绪的，对方的是有足够的缓冲区的
                // 如果写事件就绪，多路转接每次都会提醒我写事件就绪，白白浪费资源
                // 对于写的处理在select中先这样写，在EpollServer中完整的处理
                n = send(fd, msg.c_str(), msg.size(), 0);
                if (n == -1)
                {
                    LOG(ERROR, "send fail %d-%s", errno, strerror(errno));
                }
                else
                {
                    LOG(INFO, "发送成功 n = %d", n);
                }
            }
            else
            {
                LOG(INFO, "recv failed %d-%s", errno, strerror(errno));
                break;
            }
        }
    }
    void WriteHandler(int fd)
    {
        ;
    }

    static void *threadRoutinue(void *args)
    {
        pthread_detach(pthread_self());
        Tcp_Client *tcli = static_cast<Tcp_Client *>(args);
        cout << tcli->name << "启动..." << endl;
        tcli->pthis->ReadHandler(tcli->fd);
        return nullptr;
    }

    // 事件派发器
    // 让select 关心用户想要关心的文件描述符的读事件，写事件，异常事件
    // 如果该文件描述符上的某个事件就绪后，进行事件派发让它处理对应的事件
    // 函数名不应该叫这个，为了方便这里直接用这个名字，因为基类中这个函数是纯虚函数
    void Dispatcher()
    {
        LOG(INFO, "tcp server is running...");
        while (true)
        {
            int sock = AcceptHandler();
            // 我们需要创建线程，进程去对这个连接进行一个服务
            // 如果我们在主线程对这个连接进行一个服务，那么这个tcp服务器只能
            // 只能连接一个客户端。
            int* sk = new int(sock); 
            std::string name = "连接-" + std::to_string(sock);
            // 在detach模式下，线程变量的生命周期一定要长，在线程存活期间，线程不能被释放或销毁
            Thread* td = new Thread(std::bind(&TcpServer::ReadHandler,this,std::placeholders::_1),name,sk,Thread::MODE::DETACH);
            td->create();
            // cout << " ------------ " << endl;
            // Tcp_Client *tcli = new Tcp_Client;
            // tcli->pthis = this;
            // tcli->fd = sock;
            // tcli->name = name;
            // pthread_t tid;
            // pthread_create(&tid, nullptr, threadRoutinue, tcli);
        }
    }

    virtual ~TcpServer()
    {
    }

private:
    std::unordered_map<int, Client> _clients;
};